<?php

namespace App\Clients\JinShouFu;

use App\Clients\BaseClient;
use App\Models\Account;
use App\Models\AccountSub;
use App\Services\JinShouFuHelper;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\Model;
use Psr\Http\Message\ResponseInterface;

abstract class JinShouFuClient extends BaseClient
{
    protected Model $account;

    const MAX_TRYIES = 4;

    protected $isJson = true;

    /**
     * @throws Exception
     * @throws GuzzleException
     */
    public function __construct(Model $account)
    {
        parent::__construct();
        if(!($account instanceof Account) && !($account instanceof AccountSub)){
            $this->account = $account->account;
        }else{
            $this->account = $account;
        }
        if($this->account->login_status != 1
            || empty($this->account->logout_at)
            || strtotime($this->account->logout_at) <= time()
        ){
            $this->login();
        }

    }

    /**
     * @throws Exception
     * @throws GuzzleException
     */
    public function login(): void
    {
        $key = file_get_contents("https://www.jsfpay.com/totp.do?username=".$this->account->name);
        $key = json_decode($key,true);
        $cookieJar = new CookieJar();
        $key = $key["data"];
        $helper = new JinShouFuHelper;
        $key = $helper->fromKey($key);
        $totpcode = $helper->encrypt((string)(time() * 1000),$key);
        $password = $helper->encrypt($this->account->password,$key);
        $client = new Client([
            "verify"=>false,
            "http_errors"=>false,
            'cookies' => $cookieJar,
        ]);
        $postData = [
            "totpcode"=>$totpcode,
            "password"=>$password,
            "username"=>$this->account->name,
            "rememberMe"=>true,
        ];
        $response = $client->post("https://www.jsfpay.com/login.do",[
            "headers"=>[
                "User-Agent"=>"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.95 Safari/537.36",
                "referer"=>"https://www.jsfpay.com/login.do",
            ],
            "form_params"=>$postData
        ]);
        $cookies = $cookieJar->toArray();
        $cookieStr = [];
        foreach ($cookies as $cookie){
            if($cookie["Name"] == "rememberMe") continue;
            $cookieStr[] = $cookie["Name"]."=".$cookie["Value"];
        }
        $cookieStr = implode("; ",$cookieStr);
        $this->account->cookies = $cookieStr;
        $this->account->login_status = 1;
        $this->account->logout_at = date("Y-m-d H:i:s",time() + 86400);
        $this->account->save();
    }

    abstract public function execute($queryData);

    public function headers($other = []): array
    {
        $headers = [
            "User-Agent"=>'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.6045.9 Safari/537.36',
            "Referer"=>"https://www.jsfpay.com/index.do",
            "Cookie"=>$this->account->cookies,
        ];
        return array_merge($headers,$other);
    }


    /**
     * @throws Exception
     */
    protected function isLogout(ResponseInterface $response){
        $content = $response->getBody()->getContents();
        if(str_contains($content,"请输入您的手机号码")){
            $this->account->login_status = 0;
            $this->account->save();
            throw new Exception("掉线了");
        }
        return $this->isJson ? json_decode($content,true) : $content;
    }

    public function handleQeqData($postData){
        return $postData;
    }

    /**
     * @throws Exception
     * @throws GuzzleException
     */
    public function loopExecute($postData): static
    {
        $postData = $this->handleQeqData($postData);
        for($i=0;$i<=self::MAX_TRYIES;$i++){
            try{
                return $this->execute($postData);
            }catch (Exception $e){
                if($e->getMessage() == "掉线了"){
                    $this->login();
                }
                if($i == self::MAX_TRYIES) throw new Exception($e);
                sleep(5);
            }
        }
        return $this;
    }

    /**
     * 初步处理数据
     * @return void
     */
    public function handleData(): void
    {
        try{
            $this->contents = $this->contents["data"];
        }catch(Exception $e){
            var_dump($this->contents);
            throw $e;
        }
    }

    public function contents(){
        return $this->contents;
    }

    /**
     * @throws GuzzleException
     * @throws Exception
     */
    public function post($url, $postData): static
    {
        $headers = $this->headers();
        $response = $this->postData($url,$postData,$headers);
        $this->contents = $this->isLogout($response);
        $this->handleData();
        return $this;
    }

    /**
     * @throws GuzzleException
     * @throws Exception
     */
    public function get($url, $postData): static
    {
        $headers = $this->headers();
//        var_dump($headers);
//        exit();
        $response = $this->getData($url,$postData,$headers);
        $this->contents = $this->isLogout($response);
        $this->handleData();
        return $this;
    }
}
